package com.zookeeper;

import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;

/**
 * CuratorFramework 连接zookeeper
 *
 */
public class CuratorHelloworld {
    private static final String CONNECT_ADDR = "192.168.106.49:2181,192.168.106.50:2181,192.168.106.52:2181";
    private static final int SESSION_TIMEOUT = 5000;
 
    public static void main(String[] args) throws Exception {
        //重试策略，初试时间1秒，重试10次
        RetryPolicy policy = new ExponentialBackoffRetry(1000, 10);
        //通过工厂创建Curator
        CuratorFramework client = CuratorFrameworkFactory
        		.builder()
        		.connectString(CONNECT_ADDR)//服务地址及端口号，多个地址用“,”分隔
                .sessionTimeoutMs(SESSION_TIMEOUT)//会话超时时间 ，默认60000
                .connectionTimeoutMs(15000)//连接超时时间，默认15000
                .retryPolicy(policy)//重试策略
                .build();
        //开启连接
        client.start();
 
        ExecutorService executor = Executors.newCachedThreadPool();
 
        /**创建节点，creatingParentsIfNeeded()方法的意思是如果父节点不存在，则在创建节点的同时创建父节点；
         * withMode()方法指定创建的节点类型，跟原生的Zookeeper API一样，不设置默认为PERSISTENT类型。
         */
        client
        .create()
        .creatingParentsIfNeeded()//是否同时创建父节点
        .withMode(CreateMode.PERSISTENT)//创建节点的类型
        .inBackground((framework, event) -> { //绑定异步回调方法
        	//在创建节点时绑定一个回调方法，可以输出服务器的状态码以及服务器的事件类型等信息
		    System.err.println("1Code：" + event.getResultCode());
		    System.err.println("2Type：" + event.getType());
		    System.err.println("3Path：" + event.getPath());
		}, executor)
        .forPath("/super/c1", "c1内容".getBytes());//创建节点的路径
        Thread.sleep(5000); //为了能够看到回调信息
        String data = new String(client.getData().forPath("/super/c1")); //获取节点数据
        System.err.println("4"+data);
        Stat stat = client
        		.checkExists()
        		.inBackground((framework, event) -> {
        			System.err.println("判断指定节点是否存在1Code：" + event.getResultCode());
        		    System.err.println("判断指定节点是否存在2Type：" + event.getType());
        		    System.err.println("判断指定节点是否存在3Path：" + event.getPath());
        		})
        		.forPath("/super/c1"); //判断指定节点是否存在
        System.err.println("5"+stat);
        client.setData().forPath("/super/c1", "c1新内容".getBytes()); //更新节点数据
        data = new String(client.getData().forPath("/super/c1"));
        System.err.println("6"+data);
        List<String> children = client.getChildren().forPath("/super"); //获取子节点
        for(String child : children) {
            System.err.println("7"+child);
        }
        //放心的删除节点，deletingChildrenIfNeeded()方法表示如果存在子节点的话，同时删除子节点
        client.delete()
		        .guaranteed()//安全删除
		        .deletingChildrenIfNeeded()//是否同时删除子节点
		        .forPath("/super");//删除节点路径
        client.close();
    }
}